package org.uim.cricket.analyzer.analyze.impl;

import java.util.*;

import org.uim.cricket.analyzer.analyze.Alogger;
import org.uim.cricket.analyzer.analyze.CricketMatchAnalyzable;
import org.uim.cricket.analyzer.gui.AskRetiredComeBacks;
import org.uim.cricket.analyzer.gui.SelectCorrectPlayer;
import org.uim.cricket.entities.MatchPlayer;
import org.uim.cricket.entities.aggr.SingleInning;
import org.uim.cricket.entities.batting.BatsmanOutDetails;
import org.uim.cricket.entities.batting.BattingInning;
import org.uim.cricket.entities.batting.OutTypes;
import org.uim.cricket.entities.match.CricketMatch;
import org.uim.cricket.entities.partnerships.FallOfWicket;
import org.uim.cricket.util.CricketFunctions;

/**
 * Maps batsman inning and corresponding fall of wicket for that player 
 * and vice-versa.
 * 
 * @version 1.0
 * @author Isuru Madushanka
 *
 */
public class BatsmanFallOfWicketAnalyzer implements CricketMatchAnalyzable {

    private CricketFunctions cf = new CricketFunctions();
    
    public BatsmanFallOfWicketAnalyzer() {
    	
    }
	
    @Override
	public void doAnalyze(CricketMatch match, Map<String, List<MatchPlayer>> players) throws Exception {
    	if (match == null) return;
    	
    	SingleInning[] innings = match.getInnings();
		if (innings == null) return;
		
		for (int i=0;i<innings.length;i++) {
			SingleInning inn = innings[i];
			if (inn==null) continue;
			
			Alogger.debug("       ** Mapping batsman and fall of wicket at inning #" + (i+1) + "... ");
			this.mapFallOfWicketToBatsman(inn, match);
			Alogger.debug("       ** Completed... ");
		}
		
	}
    
	private void mapFallOfWicketToBatsman(SingleInning inning, CricketMatch match) {
		if (inning == null) {
			Alogger.error("Inning is empty!");
			return;
		}
		
		List<FallOfWicket> fows = inning.getFallWickets();
		List<BattingInning> batInns = null;
		if (inning.getBatInnings() != null) {
			batInns = new ArrayList<BattingInning>();
			for (int i=0; i<inning.getBatInnings().size(); i++) {
				batInns.add(inning.getBatInnings().get(i));
			}
		}
		
		if (fows == null) {
			Alogger.debug("Empty set of fall of wickets are found in inning #" + inning.getInningMatch());
			return;
		}
		if (batInns == null) {
			Alogger.debug("Empty set of battiing inning is found in inning #" + inning.getInningMatch());
			return;
		}
    	
		Alogger.debug("           Started to find out players in fall of wickets...");
		int completed = 0;
    	for (int i=0;i<fows.size();i++) {
    		
    		FallOfWicket fow = fows.get(i);
    		if (fow.getOutPlayer() == null) {
    			Alogger.debug("           No out player is found for wicket " + fow.getWicket());
    			continue;
    		}
    		
    		boolean camefromMain = false;
    		int index = this.containInBatList(batInns, fow.getOutPlayer().getTitleName());
    		Alogger.debug("Finding player : " + fow.getOutPlayer().getTitleName() + ", " + index);
    		if (index < 0) {
    			index = this.containInBatList(inning.getBatInnings(), fow.getOutPlayer().getTitleName());
    			if (index < 0) {
    				Alogger.warn("           No batting is found for out player " + fow.getOutPlayer().getTitleName() + "!");
        			continue;
    			}
    			camefromMain = true;
    		}
    		
    		if (fow.isRetiredHurt()) {
    			Alogger.warn("           + Includes a retired hurt batsman for wicket " + fow.getOutPlayer().getTitleName());
    		}
    		
    		BattingInning batinn = null;
    		if (!camefromMain) {
    			batinn = batInns.get(index);
    		} else {
    			batinn = inning.getBatInnings().get(index);
    		}
    		fow.setOutPlayer(batinn.getBatsman());
    		completed++;
    		if (batinn.getOutDetails() != null) {
    			BatsmanOutDetails outDetails = batinn.getOutDetails();
    			outDetails.setOutAsWicket(fow.getWicket());
    			outDetails.setFallofWicket(fow);
    			if (batinn.getOutDetails().getOutType() != null) {
    				OutTypes ot = batinn.getOutDetails().getOutType();
    				if (ot != OutTypes.RETIRED_HURT && fow.isRetiredHurt()) {
    					Alogger.warn("           + Special attention must be look into this match for fall of wickets.");
    					Alogger.warn("           + Because, batsman " + batinn.getBatsman().getTitleName() + " has retired out " +
    							"but he has come back to crease (" + ot.toString() + ")");
    					FallOfWicket temp = this.raiseQuestionRetired(match, inning, fow, batinn);
    					fow = temp;
    					Alogger.warn("           + he has come back in wicket " + fow.getRetiredComeBackWicket());
    				} else {
    					if (!camefromMain) {
    						batInns.remove(index);
    					}
    				}
    				
    			}
    		}
    	}
    	
    	Alogger.debug(completed + " players found in battings");
    	Alogger.debug("           Completed finding out players.");
	}

	private FallOfWicket raiseQuestionRetired(CricketMatch match, SingleInning inning, FallOfWicket wkt, BattingInning batinn) {
		AskRetiredComeBacks retireds = new AskRetiredComeBacks(null, true, match, inning, wkt, batinn);
		retireds.setVisible(true);
		FallOfWicket tfow = retireds.getFallOfWicket();
		retireds.dispose();
		return tfow;
	}
	
	private int containInBatList(List<BattingInning> list, String player) {
    	
    	if (list == null) return -1;
        List<Integer> tlist = new ArrayList<Integer>();
        
        for (int i=0;i<list.size();i++) {
            BattingInning tmp = list.get(i);
            if (tmp == null || tmp.getBatsman() == null) continue;
            if (tmp.getBatsman().getTitleName() == null) continue;
            
            if (cf.arePlayersSame(tmp.getBatsman().getTitleName(), player)) {
            	tlist.add(i);
            }
        }
        
        if (tlist.size() == 1) {
        	return tlist.get(0);
        } else if (tlist.size() > 1) {
        	List<BattingInning> bis = new ArrayList<BattingInning>();
        	for (int i=0; i<tlist.size(); i++) {
        		bis.add(list.get(tlist.get(i)));
        	}
        	
        	SelectCorrectPlayer cp = new SelectCorrectPlayer(null, true, bis, player);
        	cp.setVisible(true);
        	
        	int p = cp.getSelIndex();
        	
        	cp.dispose();
        	
        	if (p >= 0) {
        		return tlist.get(p);
        	} else {
        		return tlist.get(0);
        	}
        }
        return -1;
        
    }
}
